﻿using System.IdentityModel.Tokens.Jwt;
using System.Linq.Expressions;
using System.Security.Claims;
using System.Text;
using CommunityToolkit.Mvvm.Messaging;
using Dark_Core_Server.Models.Universal;
using Dark_Core_Server.Models.User;
using DarkSKL_Core.ArgModules;
using DarkSKL_Core.ConfigModules;
using DarkSKL_Core.MongoDBModules.Helper;
using DarkSKL_Core.MongoDBModules.Models;
using Microsoft.IdentityModel.Tokens;
using Microsoft.Net.Http.Headers;
using MongoDB.Bson;
using MongoDB.Driver;
using Serilog;
using TouchSocket.Core;

namespace Dark_Core_Server.Service
{
    /// <summary>
    /// 用户服务
    /// <br></br>
    /// <remarks>
    /// 用户创建完成后，会基于<see cref="WeakReferenceMessenger">WearReferenceMessenger</see>发送一条 UserCreated消息,消息参数类型为<see cref="UserDocument">UserDocument</see>
    /// <br></br>
    /// 用户删除完成后，会基于<see cref="WeakReferenceMessenger">WearReferenceMessenger</see>发送一条 UserDeleted消息,消息参数类型为<see cref="UserDocument">UserDocument</see>
    /// </remarks>
    /// </summary>
    public class UserService
    {
        /// <summary>
        /// 用户集合
        /// </summary>
        private readonly IMongoCollection<UserDocument> UserCollection;
        /// <summary>
        /// 用户资料集合
        /// </summary>
        private readonly IMongoCollection<UserProfileDocument> UserProfileCollection;


        #region JWT认证相关属性字段

        private readonly string Issuer;
        private readonly string SecreKeyStr;
        private readonly int ExpiresSeconds;
        private readonly string SecurityAlgorithm;
        private readonly string SymmetricSecurityKey;
        private readonly SymmetricSecurityKey SecretKey;

        #endregion


        public UserService()
        {
            
            DatabaseConfig config = new DatabaseConfig()
            {
                DatabaseName = EnvironmentConfigController.ConfigController.GetConfig<string>("DB:USER_DB_NAME"),
                User = EnvironmentConfigController.ConfigController.GetConfig<string>("DB:USER"),
                Password = EnvironmentConfigController.ConfigController.GetConfig<string>("DB:PASS"),
                Host = EnvironmentConfigController.ConfigController.GetConfig<string>("DB:HOST"),
                Port = EnvironmentConfigController.ConfigController.GetConfig<int>("DB:PORT"),
                Args = EnvironmentConfigController.ConfigController.GetConfig<string>("DB:ARGS")
            };
            UserCollection = MongodbBuilder.CreateCollection<UserDocument>(config,
                EnvironmentConfigController.ConfigController.GetConfig<string>("DB:USER_DB_COLLECTION") ?? "userUnit");
            UserProfileCollection = MongodbBuilder.CreateCollection<UserProfileDocument>(config,
                EnvironmentConfigController.ConfigController.GetConfig<string>("DB:USER_DB_PROFILE_COLLECTION") ?? "profileUnit");
            Issuer = EnvironmentConfigController.ConfigController.GetConfig<string>("AUTHOR:ISSUER") ?? "DarkSKL";
            SecreKeyStr =  EnvironmentConfigController.ConfigController.GetConfig<string>("AUTHOR:KEY") ?? "TheGlowOfTheRepublicHasNeverBeenExtinguished";
            ExpiresSeconds = EnvironmentConfigController.ConfigController.GetConfig<int>("AUTHOR:EXPIRES_SECONDS");
            SecurityAlgorithm = SecurityAlgorithms.HmacSha256;
            SecretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(SecreKeyStr));
        }

        #region Query查询
        /// <summary>
        /// 查询用户异步
        /// </summary>
        /// <param name="mode">查询模式</param>
        /// <param name="args">查询参数</param>
        /// <param name="pageNum">分页序号</param>
        /// <param name="pageSize">分页大小</param>
        /// <returns>回应消息</returns>
        public async Task<ResponseMsg<DataArrResponse<UserDocument>>> QueryUserAsync(UserQueryMode mode, string args, int pageNum = 0, int pageSize = 999)
        {
            try
            {
                var findOption = new FindOptions<UserDocument>()
                {
                    Skip = pageNum * pageSize,
                    Limit = pageSize
                };

                var findFilter = mode switch
                {
                    UserQueryMode.MultiAll => Builders<UserDocument>.Filter.Empty,
                    UserQueryMode.MultiLevel => Builders<UserDocument>.Filter.Eq(x => x.Level, Convert.ToInt32(args)),
                    UserQueryMode.SingleUsername => Builders<UserDocument>.Filter.Eq(x => x.UserName, args),
                    UserQueryMode.SingleId => Builders<UserDocument>.Filter.Eq(x => x.id, ObjectId.Parse(args)),
                    _ => throw new Exception("Unknown Query mode")
                };
                var findCount = await UserCollection.CountDocumentsAsync(findFilter);
                var findResult = await UserCollection.FindAsync(findFilter, findOption);
                var result = await findResult.ToListAsync();
                return result.ToDataArrResponse(findCount).CreateResponseMsg("查询成功", UniversalState.Success);
            }
            catch (Exception e)
            {
                Log.Error($"UserService.QueryUserAsync Exception:{e.Message}");
                return new List<UserDocument>().ToDataArrResponse(0).CreateResponseMsg($"UserService.QueryUserAsync Exception:{e.Message}", UniversalState.Error);
            }
        }

        /// <summary>
        /// 查询用户资料异步
        /// </summary>
        /// <param name="mode">查询模式</param>
        /// <param name="args">查询参数</param>
        /// <param name="pageNum">分页序号</param>
        /// <param name="pageSize">分页大小</param>
        /// <returns>回应消息</returns>
        public async Task<ResponseMsg<DataArrResponse<UserProfileDocument>>> QueryUserProfileAsync(UserQueryMode mode, string args, int pageNum = 0, int pageSize = 999)
        {
            try
            {
                var findOption = new FindOptions<UserProfileDocument>()
                {
                    Skip = pageNum * pageSize,
                    Limit = pageSize
                };

                var findFilter = mode switch
                {
                    UserQueryMode.MultiAll => Builders<UserProfileDocument>.Filter.Empty,
                    UserQueryMode.MultiNickname => Builders<UserProfileDocument>.Filter.Regex(x => x.NickName, new BsonRegularExpression(args, "i")),
                    UserQueryMode.SingleId => Builders<UserProfileDocument>.Filter.Eq(x => x.BasicId, ObjectId.Parse(args)),
                    _ => throw new Exception("Unknown Query mode")
                };
                var findCount = await UserProfileCollection.CountDocumentsAsync(findFilter);
                var findResult = await UserProfileCollection.FindAsync(findFilter, findOption);
                var result = await findResult.ToListAsync();
                return result.ToDataArrResponse(findCount).CreateResponseMsg("查询成功", UniversalState.Success);
            }
            catch (Exception e)
            {
                Log.Error($"UserService.QueryUserProfileAsync Exception:{e.Message}");
                return new List<UserProfileDocument>().ToDataArrResponse(0).CreateResponseMsg($"UserService.QueryUserProfileAsync Exception:{e.Message}", UniversalState.Error);
            }
        }

        #endregion

        #region Create创建

        /// <summary>
        /// 创建用户异步
        /// </summary>
        /// <param name="userRecord">用户文档</param>
        /// <returns></returns>
        public async Task<ResponseMsg<SimpleUserRecord>> CreateUserAsync(SimpleUserRecord userRecord)
        {
            try
            {
                var isExists = (await QueryUserAsync(UserQueryMode.SingleUsername, userRecord.username)).Data.Total > 0;
                if (isExists) throw new Exception("User already exists");

                //TODO:这里要后期针对用户的密码进行加密处理

                var documents = userRecord.ToDocument();
                await UserCollection.InsertOneAsync(documents.Item1);
                await UserProfileCollection.InsertOneAsync(documents.Item2);
                //用户创建完成后，通知其他服务
                WeakReferenceMessenger.Default.Send(documents.Item1, "UserCreated");

                return userRecord.CreateResponseMsg("创建成功", UniversalState.Success);
            }
            catch (Exception e)
            {
                Log.Error($"UserService.CreateUserAsync Exception :{e.Message}");
                return userRecord.CreateResponseMsg($"UserService.CreateUserAsync Exception :{e.Message}", UniversalState.Error);
            }
        }

        #endregion

        #region Delete删除

        /// <summary>
        /// 删除用户
        /// </summary>
        /// <param name="userRecord">用户记录</param>
        /// <returns></returns>
        public async Task<ResponseMsg<SimpleUserRecord>> DeleteUserAsync(SimpleUserRecord userRecord)
        {
            try
            {
                var userBasicUnitResult = (await QueryUserAsync(UserQueryMode.SingleUsername, userRecord.username)).Data;
                if (userBasicUnitResult.Total < 1) throw new Exception("The user does not exist.");
                await UserProfileCollection.DeleteOneAsync(x => x.BasicId == userBasicUnitResult.Rows[0].id);
                await UserCollection.DeleteOneAsync(x => x.id == userBasicUnitResult.Rows[0].id);
                //用户删除完成后，通知其他服务
                WeakReferenceMessenger.Default.Send(userBasicUnitResult.Rows[0], "UserDeleted");

                return userRecord.CreateResponseMsg("删除成功", UniversalState.Success);
            }
            catch (Exception e)
            {
                Log.Error($"UserService.DeleteUserAsync Exception:{e.Message}");
                return userRecord.CreateResponseMsg($"UserService.CreateUserAsync Exception :{e.Message}", UniversalState.Error);
            }
        }

        #endregion

        #region Update更新

        /// <summary>
        /// 更新用户信息
        /// </summary>
        /// <param name="id">用户ID</param>
        /// <param name="userProfileRecord">用户资料记录</param>
        /// <returns></returns>
        public async Task<ResponseMsg<bool>> UpdateUserProfileAsync(
            ObjectId id,
            SimpleUserProfileRecord userProfileRecord)
        {
            try
            {
                bool isExists = (await QueryUserAsync(UserQueryMode.SingleId, id.ToString())).Data.Total > 0;
                if (!isExists) throw new Exception($"The user does not exist.");
                UpdateDefinition<UserProfileDocument> updateDefinition = Builders<UserProfileDocument>.Update.Combine();
                if (userProfileRecord.AvatarUrl is not null)
                    updateDefinition = updateDefinition.Set(x => x.AvatarUrl, userProfileRecord.AvatarUrl);
                if (userProfileRecord.Signature is not null)
                    updateDefinition = updateDefinition.Set(x => x.Signature, userProfileRecord.Signature);
                if (userProfileRecord.Email is not null)
                    updateDefinition = updateDefinition.Set(x => x.Email, userProfileRecord.Email);
                if (userProfileRecord.Gender is not null)
                    updateDefinition = updateDefinition.Set(x => x.Gender, userProfileRecord.Gender);
                if (userProfileRecord.NickName is not null)
                    updateDefinition = updateDefinition.Set(x => x.NickName, userProfileRecord.NickName);
                await UserProfileCollection.UpdateOneAsync(x => x.BasicId == id, updateDefinition);
                return true.CreateResponseMsg("更新成功", UniversalState.Success);
            }
            catch (Exception e)
            {
                Log.Error($"UserService.UpdateUserAsync Exception:{e.Message}");
                return false.CreateResponseMsg($"UserService.UpdateUserAsync Exception :{e.Message}", UniversalState.Error);
            }
        }

        /// <summary>
        /// 更新用户密码
        /// </summary>
        /// <param name="userRecord">用户文档</param>
        /// <returns></returns>
        public async Task<ResponseMsg<bool>> UpdateUserPasswordAsync(SimpleUserRecord userRecord)
        {
            try
            {
                bool isExists = (await QueryUserAsync(UserQueryMode.SingleUsername,userRecord.username)).Data.Total > 0;
                if (!isExists) throw new Exception($"The user does not exist.");
                await UserCollection.UpdateOneAsync(x => x.UserName == userRecord.username,Builders<UserDocument>.Update.Set(x => x.Password,userRecord.password));
                return true.CreateResponseMsg("更新成功", UniversalState.Success);
            }
            catch (Exception e)
            {
                Log.Error($"UserService.UpdateUserAsync Exception:{e.Message}");
                return false.CreateResponseMsg($"UserService.UpdateUserAsync Exception :{e.Message}", UniversalState.Error);
            }
        }

        #endregion

        #region Author认证

        /// <summary>
        /// 给予授权
        /// </summary>
        /// <param name="userRecord">用户文档</param>
        /// <returns></returns>
        public async Task<ResponseMsg<string>> GrantAuthorization(SimpleUserRecord userRecord)
        {
            try
            {
                var findResult = await UserCollection.FindAsync(x => x.UserName == userRecord.username && x.Password == userRecord.password);
                List<UserDocument> findResultList = (await findResult.ToListAsync());
                if (findResultList.Count < 1) throw new Exception("The user does not exist or the password is incorrect.");
                UserDocument user = findResultList[0];
                var claim = new[]
                {
                    new Claim(ClaimTypes.Name, user.UserName),
                    new Claim(ClaimTypes.Role, user.Level.ToString()),
                    new Claim("ID",user.id.ToString())
                };
                Log.Information($"JwtToken生成：{user.UserName} - {user.Level} - {user.id}");
                var credentials = new SigningCredentials(SecretKey, SecurityAlgorithm);
                var token = new JwtSecurityToken(Issuer, user.UserName, claim, DateTime.Now,
                    DateTime.Now.AddSeconds(ExpiresSeconds), credentials);
                var tokenStr = new JwtSecurityTokenHandler().WriteToken(token);
                return tokenStr.CreateResponseMsg("授权成功", UniversalState.Success);

            }
            catch (Exception e)
            {
                Log.Error($"UserService.GrantAuthorization Exception:{e.Message}");
                return e.Message.CreateResponseMsg($"UserService.GrantAuthorization Exception :{e.Message}", UniversalState.Error);
            }
        }

        /// <summary>
        /// 解析Token至用户
        /// </summary>
        /// <param name="originToken">原始token</param>
        /// <returns></returns>
        public async Task<ResponseMsg<UserDocument>> ParseTokenToUser(string? originToken)
        {
            try
            {
                if (originToken is null) throw new Exception("Token is null or empty.");

                string token = originToken.Replace("Bearer ", "");
                var tokenHandler = new JwtSecurityTokenHandler();
                var payload = tokenHandler.ReadJwtToken(token).Payload;
                var claims = payload.Claims.ToList();
                string? id = claims.Find(x => x.Type == "ID")?.Value;
                if (id is null) throw new Exception("Token is invalid.");
                if (!ObjectId.TryParse(id, out var tempId)) throw new Exception("Invalid token.");

                var user = await UserCollection.FindAsync(x => x.id == tempId);
                List<UserDocument> userList = (await user.ToListAsync());
                if(userList.Count < 1) throw new Exception("The user does not exist.");
                return userList[0].CreateResponseMsg("解析成功",UniversalState.Success);
            }
            catch (Exception e)
            {
                Log.Error($"UserService.ParseTokenToUser Exception:{e.Message}");
                return new UserDocument().CreateResponseMsg("解析失败",UniversalState.Error);
            }
        }

        /// <summary>
        /// 解析HttpRequest至用户
        /// </summary>
        /// <param name="request">请求对象</param>
        /// <returns></returns>
        public async Task<ResponseMsg<UserDocument>> ParseHttpRequestToUser(HttpRequest request)
        {
            string? token = request.Headers["Authorization"];
            ResponseMsg<UserDocument> userDocument = await ParseTokenToUser(token);
            return userDocument;
        }


        #endregion




    }
}
